<?php
/**
* Provides all the basics to an object to be displayed (title, edit block, html generation,custom css).
*<p>This provides the fundations to all objects that compose a web page.</p>
*<p>Box gives all the glue to make it work:<ul>
*<li><b>title</b>: Support for title (GetTitle/SetTitle).</li>
*<li><b>custom css</b>: Support for custom styles user-editable from the client side.</li>
*<li><b>Editing</b>: A Box can have a number of "edit tabs". Each one (registered in PostInitialize) boilds down
*automagically to BoxRequest: will be shown for editing and support saving.</li>
*<li><b>Html generation</b>: by populating data (static method Box::Data) and allowing customization to 
*derived boxes using the ProcessData method.</li></ul>
*@package Box
*@author Willy Gardiol <willy@gardiol.org>
*@version 1.0
*@todo Implement a way to "upgrade" Boxes when new features are added...
*/
abstract class Box extends AtomData
{
	static public function Data( $atom_id )
	{
		$atom = AtomCache::GetAtom( $atom_id );
		if ( ($box = AtomCache::GetAtomData( $atom_id )) !== false )
		{
			return $box->ProcessData( array(
						"auth" => CoreAuth::Authorize(),

						"atom" => array("id" => $atom_id,
										"tag_cloud" => $atom->GetTagCloud() ),

						"title" => array("text" => $box->title,
										"show" => $box->show_title),

						"template" => $box->template,

						"css" => $box->css,
						"css_text" => $box->GetStyle(),

						"data" => $box->GetStorage(),

						"children" => $box->GetChildren(),

						"edit_type" => $box->edit_type,

						) );
		}
		return false;
	}
	static public function Create($type,$title, $tags )
	{
		$atom = new Atom( $tags, new $type( $title ) );
		return $atom->GetId();
	}
	static public function Draw( $atom_id )
	{
		$html = new HtmlTemplate( "core:box", array("atom_id" => $atom_id));
		$html->DrawHtml();
	}

	/**
	* Workaround for registering Box descriptions on PHP < 5.3.0.
	*- Problem: before PHP 5.3.0 we cannot to $class_type::Description();
	*- Solution: make description a public static method and popoulate it on each startup.
	*@todo When migrating to PHP > 5.3.0, redo this and simply use a static Description method.
	*/
	static public $description = array();
 
	private $edit_type = "popup";
	private $edit_tabs = array();
	private $title = "title";
	private $show_title = false;
	private $template = false;
	private $css = array();

	/**
	* Any Box have a title and css that can be personalized by the end-user from client side.
	*@param string $title Box title (mandatory! please use meaningful titles).
	*@param string $edit_type Can be either "popup" or "inline", defines how the edit block is displayed.
	*/
	protected function __construct( $title, $edit_type, $template )
	{
		parent::__construct( array() );
		$this->title = $title;
		$this->template = $template;
		$this->edit_type = $edit_type;

		if ( ($this->edit_type !== "inline" ) &&
		     ($this->edit_type !== "popup") )
			throw new Exception("Sorry but edit_type '".$this->edit_type."' is invalid!");

		$this->AddEditTab(	"core:box_config",
							I18N("Edit title, style and tags"),
							I18N("Save title, style and tag"),
							"SaveBoxConfig" );
	}

	final protected function AddEditTab( $template, $title, $button, $callback )
	{
		$this->edit_tabs[] = array( "template" => $template,
									"title" => $title,
									"button" => $button,
									"callback" => array($this, $callback) );
	}

	final public function SaveTab( $tab_id, $calling_request )
	{
		if ( isset( $this->edit_tabs[$tab_id] ) )
		{
			if ( call_user_func( $this->edit_tabs[$tab_id]["callback"], $calling_request ) === false )
				$calling_request->SetError( I18N("Unable to save: internal error.") );
		}
		else
			$calling_request->SetError( I18N("Sorry but the request is invalid.") );
	}

	final public function ListEditTabs()
	{
		$ret = array();
		foreach ($this->edit_tabs as $id => $tab )
			$ret[$id] = $tab["title"];
		return $ret;
	}

	final public function GetEditTab( $tab_id )
	{
		if ( isset( $this->edit_tabs[$tab_id] ) )
			return $this->edit_tabs[$tab_id];
		return false;
	}

	/**
	*Read title.
	*@return string
	*/
	public function GetTitle()
	{
		return $this->title;
	}
	/**
	*Set/replace title.
	*When updating a box title all its parents get their timestamp updated as well. This is to ensure that any
	*modifications can be properly processed upstream if needed.
	*@param string $title The title to set 
	*@todo Decide if this parents timestamp update is required for any Set or only title
	*/
	public function SetTitle( $title )
	{
		if ( $title === $this->title )
			return false;
		$myatom = AtomCache::GetAtom( $this->GetId() );
		foreach ( $myatom->GetParents() as $parent )
		{
			$atom = AtomCache::GetAtom($parent);
			$atom->SetLastUpdate();
		}
		$this->title = $title;
		$this->SetModified();
		return true;
	}

	protected function GetStyle()
	{
		$str = "";
		foreach ( $this->css as $k => $v )
			$str .= "$k: $v;";
		return $str;
	}

	/**
	*For derived classes to create their HTML code
	*@return mixed Html code or HtmlTag tree
	*/
	protected function ProcessData( $data )
	{
		return $data;
	}

	/**
	* Simplify access to Atom leaves. Add a new leaf.
	*@param string $leaf_id Id for new leaf
	*@param string $id atom id to set as leaf
	*/
	public function SetChild( $leaf_id, $id )
	{
		$atom = AtomCache::GetAtom( $this->GetId() );
		return $atom->SetLeaf( $leaf_id, $id );
	}
	/**
	* Simplify access to Atom leaves. Remove a leaf.
	*@param string $leaf_id Id for new leaf
	*/
	public function RemoveChild( $leaf_id )
	{
		$atom = AtomCache::GetAtom( $this->GetId() );
		return $atom->UnsetLeaf( $leaf_id, false );
	}
	/**
	* Simplify access to Atom leaves. List all leaves.
	*@return array list of leaves
	*/
	public function GetChildren()
	{
		$atom = AtomCache::GetAtom( $this->GetId() );
		return $atom->GetLeaves();
	}
	/**
	* Simplify access to Atom leaves. Get a leaf.
	*@param string $leaf_id Id leaf to get
	*@return string Atom id of leaf
	*/
	public function GetChild( $leaf_id )
	{
		$atom = AtomCache::GetAtom( $this->GetId() );
		return $atom->GetLeaf( $leaf_id );
	}

	protected function SaveBoxConfig( $request )
	{
		if ( ($title = Core::PostVar("box_title", false, "string")) !== false )
			$this->SetTitle( $title ) && $request->SetReload();
		if (	(($css = Core::PostVar("box_css", false, "serialized"))!== false) &&
				(($css==="")||(is_array($css))) &&
				( $css != $this->css) )
		{
			$this->css = $css;
			$request->SetReload();
			$this->SetModified();
		}
		if ( ($new_tags = Core::PostVar("box_tags", false, "sequence")) !== false )
		{
			$atom = AtomCache::GetAtom($this->GetId());
			$atom->SetTagCloud( $new_tags ) && $request->SetReload();
		}
		if ( ($show_title = Core::PostVar("show_title", false, "bool")) !== $this->show_title )
		{
			$this->show_title = $show_title;
			$this->SetModified();
			$request->SetReload();
		}
		var_dump( $show_title );
		var_dump( $css );
		var_dump($title);
		echo I18N("Saved successfully.");
	}
}
?>